package com.atguigu.juc.day02.communication;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 题目：使用四个线程互相配合，打印四种不同字符。
 * 四种字符分别是数字、字母、*、$
 * 打印效果举例：
 * 1a*$
 * 2b*$
 * 3c*$
 * ……
 */
public class Demo02Fixed {

    private Lock lock = new ReentrantLock();
    private Condition conditionDigital = lock.newCondition();
    private Condition conditionAlphabet = lock.newCondition();
    private Condition conditionStar = lock.newCondition();
    private Condition conditionDollar = lock.newCondition();

    private int step = 1;
    private int digital = 1;
    private char alphabet = 'a';

    public void printDigital() {
        try {
            lock.lock();
            while (step % 4 != 1) {
                // 不该打数字的时候，当前线程等待
                conditionDigital.await();
            }

            // 核心操作
            System.out.print(digital++);

            // 总步骤 +1
            step++;

            // 精确唤醒打印字符的线程
            conditionAlphabet.signal();

        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            lock.unlock();
        }
    }

    public void printAlphabet() {
        try {
            lock.lock();
            while (step % 4 != 2) {
                // 不该打数字的时候，当前线程等待
                conditionAlphabet.await();
            }

            // 核心操作
            System.out.print(alphabet++);

            // 总步骤 +1
            step++;

            // 精确唤醒打印星号的线程
            conditionStar.signal();

        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            lock.unlock();
        }
    }
    public void printStar() {
        try {
            lock.lock();
            while (step % 4 != 3) {
                // 不该打数字的时候，当前线程等待
                conditionStar.await();
            }

            // 核心操作
            System.out.print("*");

            // 总步骤 +1
            step++;

            // 精确唤醒打印美元的线程
            conditionDollar.signal();

        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            lock.unlock();
        }
    }

    public void printDollar() {
        try {
            lock.lock();
            while (step % 4 != 0) {
                // 不该打数字的时候，当前线程等待
                conditionDollar.await();
            }

            // 核心操作
            System.out.println("$");

            // 总步骤 +1
            step++;

            // 精确唤醒打印星号的线程
            conditionDigital.signal();

        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {

        Demo02Fixed demo = new Demo02Fixed();

        new Thread(()->{
            for (int i = 0; i < 30; i++) {
                demo.printDigital();
            }
        }, "thread-a").start();

        new Thread(()->{
            for (int i = 0; i < 30; i++) {
                demo.printAlphabet();
            }
        }, "thread-b").start();

        new Thread(()->{
            for (int i = 0; i < 30; i++) {
                demo.printStar();
            }
        }, "thread-c").start();

        new Thread(()->{
            for (int i = 0; i < 30; i++) {
                demo.printDollar();
            }
        }, "thread-d").start();

    }
}
